﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;

namespace STCommon.View
{
    public partial class AutoSizeComboBox : ComboBox
    {
        public AutoSizeComboBox()
        {
            InitializeComponent();

            m_Items = new AutoSizeComboBoxCollection(this);
            m_Items.ListChanged += new PropertyChangedEventHandler(OnItemsChanged);
        }

        void OnItemsChanged(object sender, PropertyChangedEventArgs e)
        {
            if (AutoSize)
            {
                ResizeControl();
            }
        }

        protected override void OnAutoSizeChanged(EventArgs e)
        {
            base.OnAutoSizeChanged(e);

            ResizeControl();
        }

        protected override void RefreshItems()
        {
            base.RefreshItems();

            ResizeControl();
        }

        public override void ResetText()
        {
            base.ResetText();

            ResizeControl();
        }

        private void ResizeControl()
        {
            Graphics tempGraphics = Graphics.FromHwnd(base.Handle);
            Size newSize;

            if (AutoSize)
            {
                newSize = tempGraphics.MeasureString(base.Text, base.Font).ToSize();

                // Find longest string
                foreach (object item in Items)
                {
                    SizeF itemSize = tempGraphics.MeasureString(base.GetItemText(item), base.Font);

                    if (itemSize.Width > newSize.Width)
                    {
                        newSize = Size.Ceiling(itemSize);
                    }
                }
            }
            else
            {
                newSize = m_BaseSize;
            }

            // Set size to longest string in base in order not to overwrite
            //  our default
            base.Size = new Size((int)Math.Ceiling(newSize.Width + 16.0), newSize.Height);

            tempGraphics.Dispose();
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public override bool AutoSize
        {
            get { return base.AutoSize; }
            set { base.AutoSize = value; }
        }

        public new Size Size
        {
            get { return base.Size; }
            set
            {
                if (m_BaseSize != value)
                {
                    m_BaseSize = value;

                    base.Size = m_BaseSize;
                }
            }
        }

        [Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [MergableProperty(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Localizable(true)]
        public new AutoSizeComboBoxCollection Items
        {
            get { return m_Items; }
        }

        [ListBindable(false)]
        public class AutoSizeComboBoxCollection : IList, ICollection, IEnumerable
        {
            public AutoSizeComboBoxCollection(ComboBox owner)
            {
                Debug.Assert(owner != null);

                m_Owner = owner;
            }

            public int Count { get { return m_Owner.Items.Count; } }
            public bool IsReadOnly { get { return m_Owner.Items.IsReadOnly; } }
            public bool IsSynchronized { get { return true; } }
            public object SyncRoot { get { return m_Owner.Items; } }
            public bool IsFixedSize { get { return false; } }

            [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
            [Browsable(false)]
            public virtual object this[int index]
            {
                get { return m_Owner.Items[index]; }
                set { m_Owner.Items[index] = value; }
            }

            public int Add(object item)
            {
                int index = m_Owner.Items.Add(item);

                TriggerListChangedEvent();

                return index;
            }

            public void AddRange(object[] items)
            {
                m_Owner.Items.AddRange(items);

                TriggerListChangedEvent();
            }

            public void Clear()
            {
                m_Owner.Items.Clear();

                TriggerListChangedEvent();
            }

            public bool Contains(object value)
            {
                return m_Owner.Items.Contains(value);
            }

            public void CopyTo(object[] destination, int arrayIndex)
            {
                m_Owner.Items.CopyTo(destination, arrayIndex);
            }

            public void CopyTo(Array destination, int arrayIndex)
            {
                destination = Array.CreateInstance(typeof(object), m_Owner.Items.Count);

                for (int i = 0; i < m_Owner.Items.Count; ++i)
                {
                    object item = m_Owner.Items[i];

                    destination.SetValue(item, i);
                }
            }
            public IEnumerator GetEnumerator()
            {
                return m_Owner.Items.GetEnumerator();
            }

            public int IndexOf(object value)
            {
                return m_Owner.Items.IndexOf(value);
            }

            public void Insert(int index, object item)
            {
                m_Owner.Items.Insert(index, item);

                TriggerListChangedEvent();
            }

            public void Remove(object value)
            {
                m_Owner.Items.Remove(value);

                TriggerListChangedEvent();
            }

            public void RemoveAt(int index)
            {
                m_Owner.Items.RemoveAt(index);

                TriggerListChangedEvent();
            }

            private void TriggerListChangedEvent()
            {
                if (ListChanged != null)
                {
                    ListChanged(this, new PropertyChangedEventArgs("List"));
                }
            }

            public event PropertyChangedEventHandler ListChanged;

            private ComboBox m_Owner = null;
        }

        private Size m_BaseSize;
        private AutoSizeComboBoxCollection m_Items = null;
    }
}
